#ifndef DockAreaWidgetH
#define DockAreaWidgetH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   DockAreaWidget.h
/// \author Uwe Kindler
/// \date   24.02.2017
/// \brief  Declaration of CDockAreaWidget class
//============================================================================


//============================================================================
//                                   INCLUDES
//============================================================================
#include <QFrame>

#include "ads_globals.h"
#include "AutoHideTab.h"
#include "DockWidget.h"

QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter)
QT_FORWARD_DECLARE_CLASS(QAbstractButton)

namespace ads
{
struct DockAreaWidgetPrivate;
class CDockManager;
class CDockContainerWidget;
class DockContainerWidgetPrivate;
class CDockAreaTitleBar;
class CDockingStateReader;


/**
 * DockAreaWidget 管理多个 DockWidgets 的实例。
 * 它显示一个可点击的标题选项卡，当点击时会切换到与标题关联的内容。
 */
class ADS_EXPORT CDockAreaWidget : public QFrame
{
    Q_OBJECT
private:
    DockAreaWidgetPrivate* d; ///< 私有数据 (pimpl)
    friend struct DockAreaWidgetPrivate;
    friend class CDockContainerWidget;
    friend class DockContainerWidgetPrivate;
    friend class CDockWidgetTab;
    friend struct DockWidgetPrivate;
    friend class CDockWidget;
    friend struct DockManagerPrivate;
    friend class CDockManager;
    friend class CAutoHideDockContainer;
    
    void onDockWidgetFeaturesChanged();
    
private Q_SLOTS:
    void onTabCloseRequested(int Index);
    /**
     * 重新排列从 fromIndex 到 toIndex 的 DockWidget 的索引位置，
     * 如果一个选项卡从一个索引位置拖动到另一个索引位置。
     */
    void reorderDockWidget(int fromIndex, int toIndex);
    /*
     * 根据是否包含在自动隐藏容器中来更新自动隐藏按钮的选中状态
     */
    void updateAutoHideButtonCheckState();
    /*
     * 更新标题栏按钮的工具提示
     */
    void updateTitleBarButtonsToolTips();
    /**
     * 根据容器中的 DockAreaWidget 位置计算自动隐藏侧边栏位置
     */
    SideBarLocation calculateSideTabBarArea() const;
    
protected:
#ifdef Q_OS_WIN
    /**
     * 重新实现 QWidget::event 以处理 QEvent::PlatformSurface
     * 这是为了解决自 Qt 版本 5.12.7 以来存在的问题 #294 Tab 刷新问题与 QGLWidget。
     * 所以这个函数在这里是为了解决 Qt 的问题。
     */
    virtual bool event(QEvent *event) override;
#endif
    
    /**
     * 将 DockWidget 插入到 DockArea 中。
     * 所有 DockWidget 在一个带有选项卡的堆叠布局中进行分组。
     * index 参数表示新 DockWidget 在选项卡栏和堆叠布局中的索引。
     * 如果 Activate 参数为 true，则新的 DockWidget 将成为堆叠布局中的活动窗口。
     */
    void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true);
    
    /**
     * 将新的 DockWidget 添加到 DockArea 中。
     * 所有 DockWidget 在一个带有选项卡的堆叠布局中进行分组。
     */
    void addDockWidget(CDockWidget* DockWidget);
    
    /**
     * 从 DockArea 中移除给定的 DockWidget
     */
    void removeDockWidget(CDockWidget* DockWidget);
    
    /**
     * 当 DockWidget 打开或关闭时由 DockWidget 调用
     */
    void toggleDockWidgetView(CDockWidget* DockWidget, bool Open);
    
    /**
     * 这是一个辅助函数，用于获取下一个要激活的打开的 DockWidget，
     * 如果给定的 DockWidget 将被关闭或移除。
     * 该函数返回应该被激活的下一个窗口，如果在此区域中没有更多打开的窗口，则返回 nullptr。
     */
    CDockWidget* nextOpenDockWidget(CDockWidget* DockWidget) const;
    
    /**
     * 返回给定 DockWidget 在内部布局中的索引
     */
    int index(CDockWidget* DockWidget);
    
    /**
     * 如果已知 dock 不包含任何可见内容（任何打开的 dock widget），则调用此函数。
     */
    void hideAreaWithNoVisibleContent();
    
    /**
     * 更新 dock 区域布局和组件的可见性
     */
    void updateTitleBarVisibility();
    
    /**
     * 这是用于设置当前窗口的内部私有函数。
     * 此函数由公共的 setCurrentDockWidget() 函数和 dock manager 在恢复状态时调用。
     */
    void internalSetCurrentDockWidget(CDockWidget* DockWidget);
    
    /**
     * 标记选项卡菜单需要更新
     */
    void markTitleBarMenuOutdated();
    
    /*
     * 根据是否为顶级窗口来更新标题栏按钮的可见性
     */
    void updateTitleBarButtonVisibility(bool IsTopLevel) const;
    
protected Q_SLOTS:
    void toggleView(bool Open);
    
public:
    using Super = QFrame;
    
    /**
     * Dock 区域相关标志
     */
    enum eDockAreaFlag
    {
        HideSingleWidgetTitleBar = 0x0001,
        DefaultFlags = 0x0000
    };
    Q_DECLARE_FLAGS(DockAreaFlags, eDockAreaFlag)
    
    /**
     * 默认构造函数
     */
    CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent);
    
    /**
     * 虚析构函数
     */
    virtual ~CDockAreaWidget();
    
    /**
     * 返回此 dock area 所属的 dock manager 对象
     */
    CDockManager* dockManager() const;
    
    /**
     * 返回此 dock area widget 所属的 dock container widget，如果没有则返回 0
     */
    CDockContainerWidget* dockContainer() const;
    
    /**
     * 返回此 dock area widget 所属的自动隐藏 dock container widget，如果没有则返回 0
     */
    CAutoHideDockContainer* autoHideDockContainer() const;
    
    /**
     * 如果 dock area 在自动隐藏容器中，则返回 true
     */
    bool isAutoHide() const;
    
    /**
     * 设置当前自动隐藏 dock container
     */
    void setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer);
};

    /** 
 * 返回此区域中所有停靠窗口的最大minimumSizeHint()。 
 * 如果添加或删除了停靠窗口，则会更新最小大小提示。 
 */ 
virtual QSize minimumSizeHint() const override; 
 
/** 
 * 返回标题栏区域的矩形 
 */ 
QRect titleBarGeometry() const; 
 
/** 
 * 返回内容区域的矩形 
 */ 
QRect contentAreaGeometry() const; 
 
/** 
 * 返回此区域中的停靠窗口数量 
 */ 
int dockWidgetsCount() const; 
 
/** 
 * 返回此停靠区域中的所有停靠窗口的列表。 
 * 此列表包含打开和关闭的停靠窗口。 
 */ 
QList<CDockWidget*> dockWidgets() const; 
 
/** 
 * 返回此区域中打开的停靠窗口数量 
 */ 
int openDockWidgetsCount() const; 
 
/** 
 * 返回未关闭的停靠窗口列表。 
 */ 
QList<CDockWidget*> openedDockWidgets() const; 
 
/** 
 * 按索引返回一个停靠窗口 
 */ 
CDockWidget* dockWidget(int Index) const; 
 
/** 
 * 返回当前活动的停靠窗口的索引，如果没有活动的停靠窗口（即所有停靠窗口均已关闭），则返回-1 
 */ 
int currentIndex() const; 
 
/** 
 * 返回停靠窗口列表中第一个打开的停靠窗口的索引。 
 * 出于性能原因，此函数存在。通常可以从openedDockWidgets()函数返回的列表中获取第一个停靠窗口。 
 * 但是，该函数在找到第一个打开的停靠窗口后停止，而不是枚举所有停靠窗口。 
 * 如果没有打开的停靠窗口，则函数返回-1。 
 */ 
int indexOfFirstOpenDockWidget() const; 
 
/** 
 * 返回当前活动的停靠窗口，如果没有活动的停靠窗口（即所有停靠窗口均已关闭），则返回nullptr 
 */ 
CDockWidget* currentDockWidget() const; 
 
/** 
 * 显示具有给定停靠窗口的选项卡 
 */ 
void setCurrentDockWidget(CDockWidget* DockWidget); 
 
/** 
 * 将状态保存到给定的流中 
 */ 
void saveState(QXmlStreamWriter& Stream) const; 
 
/** 
 * 恢复一个停靠区域。 
 * \see restoreChildNodes()了解详细信息 
 */ 
static bool restoreState(CDockingStateReader& Stream, CDockAreaWidget*& CreatedWidget, 
	bool Testing, CDockContainerWidget* ParentContainer); 
 
/** 
 * 此函数返回此区域中所有停靠窗口的停靠窗口特性。 
 * 使用位与运算符将所有停靠窗口的标志组合在一起。 
 * 这意味着，如果只有一个停靠窗口不支持某个标志，整个停靠区域都不支持该标志。 
 * 例如，如果此区域中的一个停靠窗口不可关闭，则整个停靠区域都不可关闭。 
 */ 
CDockWidget::DockWidgetFeatures features(eBitwiseOperator Mode = BitwiseAnd) const; 
 
/** 
 * 根据给定的标题栏按钮标识符返回标题栏按钮 
 */ 
QAbstractButton* titleBarButton(TitleBarButton which) const; 
 
/** 
 * 如果可见性发生变化，则更新关闭按钮 
 */ 
virtual void setVisible(bool Visible) override; 
 
/** 
 * 配置此特定停靠区域允许停靠的区域 
 */ 
void setAllowedAreas(DockWidgetAreas areas); 
 
/** 
 * 返回此特定停靠区域允许停靠的区域的标志 
 */ 
DockWidgetAreas allowedAreas() const; 
 
/** 
 * 返回此停靠区域的标题栏 
 */ 
CDockAreaTitleBar* titleBar() const; 
 
/** 
 * 返回停靠区域标志 - 一组标志，用于配置停靠区域的外观和特性。 
 * \see setDockAreaFlasg() 
 */ 
DockAreaFlags dockAreaFlags() const; 
 
/** 
 * 设置停靠区域标志 - 一组标志，用于配置停靠区域的外观和特性 
 */ 
void setDockAreaFlags(DockAreaFlags Flags); 

	/**
 * 设置此小部件的停靠区域标志，如果on为true，则设置标志；否则清除标志。
 */
void setDockAreaFlag(eDockAreaFlag Flag, bool On);

/**
 * 如果区域只包含一个停靠小部件，并且该小部件是其管理器的中心小部件，则返回true。
 */
bool isCentralWidgetArea() const;

/**
 * 如果区域包含其管理器的中心小部件，则返回true。
 */
bool containsCentralWidget() const;

/**
 * 如果此停靠区域是容器中唯一可见的区域，则返回true。
 */
bool isTopLevelArea() const;

public Q_SLOTS:
/**
 * 激活给定标签索引的选项卡。
 * 如果给定标签的停靠小部件不可见，则此函数调用将使其可见。
 */
void setCurrentIndex(int index);

/**
 * 关闭该停靠区域及其内部的所有停靠小部件。
 */
void closeArea();

/**
 * 将停靠区域设置为自动隐藏模式或普通模式。
 * 如果停靠区域切换到自动隐藏模式，则所有可固定的停靠小部件将添加到侧边栏。
 */
void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone, int TabIndex = -1);

/**
 * 根据当前状态，将停靠区域切换到自动隐藏模式或反之亦然。
 */
void toggleAutoHide(SideBarLocation Location = SideBarNone);

/**
 * 此函数关闭除此区域以外的所有区域。
 */
void closeOtherAreas();

/**
 * 如果区域的DockWidgetFloatable标志为true，则将停靠区域移动到其自己的浮动小部件中。
 */
void setFloating();

Q_SIGNALS:
/**
 * 当用户单击索引处的选项卡时，发出此信号。
 */
void tabBarClicked(int index);

/**
 * 当选项卡栏的当前选项卡即将更改时，发出此信号。新的当前选项卡具有给定的索引，如果没有新选项卡，则为-1。
 * @param index
 */
void currentChanging(int index);

/**
 * 当选项卡栏的当前选项卡更改时，发出此信号。新的当前选项卡具有给定的索引，如果没有新选项卡，则为-1。
 * @param index
 */
void currentChanged(int index);

/**
 * 如果通过切换视图函数切换此停靠区域的可见性，则发出此信号。
 */
void viewToggled(bool Open);
}; // class DockAreaWidget
} // namespace ads

Q_DECLARE_OPERATORS_FOR_FLAGS(ads::CDockAreaWidget::DockAreaFlags)
//-----------------------------------------------------------------------------
#endif // DockAreaWidgetH
